/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package DeMaSoft;
import java.util.*;
import antcolony.*;
import org.json.simple.*;

/**
 *
 * @author Fernando
 */
public class GestorVehiculos {
    public static final int numAutos = 20;
    public static final int numMotos = 40;
    public static final int capacidadCarros = 25;
    public static final int capacidadMotos = 4;
    public static final float velocidadCarros = 30;
    public static final float velocidadMotos = 60;
    private ArrayList<Vehicle> _vehiculos;
    private static GestorVehiculos _instance;
    
    public String getJson(){
        String hora = Reloj.getInstancia().getFechaString("hh:mm");
        JSONObject obj = new JSONObject();
        JSONArray vehiculosJson = new JSONArray();
        int tam = this._vehiculos.size();
        for(int i =0; i < tam ; i++){
            JSONObject v = new JSONObject();
            JSONArray ruta = new JSONArray();
            int tamRuta = this._vehiculos.get(i).getRuta().size();
            for(int j =0; j < tamRuta;j++){
                JSONObject punto = new JSONObject();
                punto.put("x", this._vehiculos.get(i).getRuta().get(j).getPosX());
                punto.put("y", this._vehiculos.get(i).getRuta().get(j).getPosY());
                ruta.add(punto);
            }
            v.put("ruta",ruta);
            v.put("x",this._vehiculos.get(i).getPosicion().getPosX());
            v.put("y",this._vehiculos.get(i).getPosicion().getPosY());
            vehiculosJson.add(v);
        }
        obj.put("vehiculos", vehiculosJson);
        obj.put("reloj",hora);
        return obj.toJSONString();
    }
    
    public void asignarRutas(ArrayList<ArrayList<Node>> bestRoutes){
        Mapa map =RouteCalculator.mapa;
        for(int i=0;i<bestRoutes.size();i++){
            ArrayList<Punto> ruta = new ArrayList<>();
            ArrayList<Node> solucion = bestRoutes.get(i);
            for(int j=1;j< solucion.size();j++){
                int indAnt = solucion.get(j-1).getX()*RouteCalculator.mapa.getAlto()+solucion.get(j-1).getY();
                int ind=solucion.get(j).getX()*RouteCalculator.mapa.getAlto()+solucion.get(j).getY();
                Punto p1 = map.getPuntos().get(indAnt);
                Punto p2 = map.getPuntos().get(ind);
                ArrayList<Punto> segment = GestorVehiculos.Astar(p1,p2);
                if(j!=1)segment.remove(0);
                ruta.addAll(segment);
                
            }
            this._vehiculos.get(i).setRuta(ruta);
        }
    }
    
    public void actualizarVehiculosYOrdenes(int tiempo,ArrayList<OrdenEntrega> ordenes){
        int size = this._vehiculos.size();
        for(int i=0;i<size;i++){
            this._vehiculos.get(i).avanzar(tiempo,ordenes);
        }
    }
    
    public static float geomDistance(Punto p1, Punto p2){
        int x1 = p1.getPosX();
        int x2 = p2.getPosX();
        int y1 = p1.getPosY();
        int y2 = p2.getPosY();
        return (float) Math.sqrt((x1-x2)*(x1-x2) +(y1-y2)*(y1-y2));
    }

    private static ArrayList<Punto> getCheapestRoute(ArrayList<ArrayList<Punto>> routes, Punto p) {
        ArrayList<Punto> cheapest = null;
        float minCost = Float.POSITIVE_INFINITY;
        for(int i=0;i<routes.size();i++){
            ArrayList<Punto> current = routes.get(i);
            //añadir el costo de las aristas en caso se necesite aristas de difernte peso
            float cost = geomDistance(current.get(current.size()-1),p);
            if(cost <= minCost){
                minCost = cost;
                cheapest = current;
            }
        }
        routes.remove(cheapest);
        return cheapest;
    }
        
    public static ArrayList<Punto> Astar(Punto p1, Punto p2){
        ArrayList<ArrayList<Punto>> routes = new ArrayList<>();
        ArrayList<Punto> visitados = new ArrayList<>();
        //inicializar una ruta con el nodo inicial
        ArrayList<Punto> route = new ArrayList<>();
        route.add(p1);
        routes.add(route);
        
        while(visitados.size() !=RouteCalculator.mapa.getPuntos().size()){
            ArrayList<Punto> cheapest = getCheapestRoute(routes,p2);
            Punto ultimo = cheapest.get(cheapest.size()-1);
            if(ultimo == p2)return cheapest;
            for(int i=0;i < ultimo.getAdj().size();i++){
                if(ultimo.getAdj().get(i).isDisponible() && !visitados.contains(ultimo.getAdj().get(i))){
                    ArrayList<Punto> nuevaRuta = (ArrayList<Punto>)cheapest.clone();
                    nuevaRuta.add(ultimo.getAdj().get(i));
                    routes.add(nuevaRuta);
                }
            }
            visitados.add(ultimo);
        }
        return null;
    }

    public ArrayList<Vehicle> getVehiculos() {
        return _vehiculos;
    }

    public void setVehiculos(ArrayList<Vehicle> _vehiculos) {
        this._vehiculos = _vehiculos;
    }
    
    private GestorVehiculos(){
        
    }
    
    public static GestorVehiculos getInstancia(){
        if(_instance == null)_instance = new GestorVehiculos();;
        return _instance;
    } 
    
    public void createVehicles() {
        _vehiculos = new ArrayList<>();
        for (int i = 0; i < numAutos; i++) {
            Vehicle v = new Vehicle(capacidadCarros, velocidadCarros);
            v.setPosicion(RouteCalculator.almacen.getUbicacion());
            _vehiculos.add(v);
        }
        for (int i = 0; i < numMotos; i++) {
            Vehicle v = new Vehicle(capacidadMotos, velocidadMotos);  
            v.setPosicion(RouteCalculator.almacen.getUbicacion());
            _vehiculos.add(v);
        }
    }
    
}
